package com.yswy.app.service.impl;

import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yswy.app.dto.AddTransferOrderVo;
import com.yswy.common.enums.WxHdActionTypeEnums;
import com.yswy.common.enums.WxPayMethodEnums;
import com.yswy.common.utils.StringUtils;
import com.yswy.common.wxOrder.V3.WxPayConfigV3;
import com.yswy.common.wxOrder.V3.wxPayV3Transfer.*;
import com.yswy.common.zfbOrder.ZfbOrderUtil;
import com.yswy.domain.common.BasePojo;
import com.yswy.domain.vo.dto.TransferOrderVo;
import com.yswy.app.dto.TransferWayVo;
import com.yswy.app.service.*;
import com.yswy.common.enums.PayMethodEnums;
import com.yswy.common.utils.DateUtils;
import com.yswy.common.utils.OrderNoCenter;
import com.yswy.common.utils.redis.RedisConstants;
import com.yswy.common.utils.redis.RedisUtil;
import com.yswy.common.zfbOrder.TransferRequestDto;
import com.yswy.common.zfbOrder.ZfbKeyVo;
import com.yswy.domain.entity.*;
import com.yswy.domain.mapper.TransferConfigMapper;
import com.yswy.domain.mapper.TransferOrderMapper;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Slf4j
@Service
public class TransferOrderServiceImpl extends ServiceImpl<TransferOrderMapper, TransferOrder>
        implements TransferOrderService {

    @Autowired
    private SysConfigService configService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserThirdPartyAccountService userThirdPartyAccountService ;



    @Autowired
    private ZfbPayKeyService zfbPayKeyService ;

    @Autowired
    private TransferConfigMapper transferConfigMapper ;

    @Resource
    private UserWxOpenService userWxOpenService;

    @Autowired
    private UserLoginLogService loginLogService;

    @Value("${pagkename1}")
    private String pagekname1;


    @Override
    public List<TransferOrderVo> ListTransferOrder(Long userId) {
        List<TransferOrder> list = list(new LambdaQueryWrapper<TransferOrder>().eq(TransferOrder::getUserId , userId)
                .orderByDesc(BasePojo::getCreateTime ));
        List<TransferOrderVo> transferOrderVos = new ArrayList<>();
        for (TransferOrder t:list
             ) {
            transferOrderVos.add(new TransferOrderVo(t));
        }

        return transferOrderVos;
    }



    @Override
    public TransferOrder  transferOrder(AddTransferOrderVo addTransferOrderVo ) {

        Integer paymentType =addTransferOrderVo.getPaymentType() ;
        Long userId = addTransferOrderVo.getUserId();
        Integer money = addTransferOrderVo.getMoney();
        TransferConfig transferConfig = addTransferOrderVo.getTransferConfig();


        //判断是否绑定微信
        LambdaQueryWrapper<UserThirdPartyAccount> lambdaQueryWrapper = new LambdaQueryWrapper<UserThirdPartyAccount>()
                .eq(UserThirdPartyAccount::getUserId, userId);
        List<UserThirdPartyAccount> userThirdPartyAccounts ;
        System.out.println(transferConfig.getZfbMinNum());
        System.out.println(money);
        if (paymentType == 1){
            if (!transferConfig.getOpenWx()){
                throw new IllegalArgumentException("暂不支持微信提现");
            }
            if (transferConfig.getWxMinNum() > money){
                throw new IllegalArgumentException("金额过小，不支持提现");
            }
            userThirdPartyAccounts = userThirdPartyAccountService
                    .list(lambdaQueryWrapper.eq(UserThirdPartyAccount::getAccountType , 1));
        }else if (paymentType == 0){
            if (!transferConfig.getOpenZfb()){
                throw new IllegalArgumentException("暂不支持支付宝提现");
            }
            if (transferConfig.getZfbMinNum() > money){
                throw new IllegalArgumentException("金额过小，不支持提现");
            }
            userThirdPartyAccounts = userThirdPartyAccountService
                    .list(lambdaQueryWrapper.eq(UserThirdPartyAccount::getAccountType , 0));
        }else {
            throw new IllegalArgumentException("收款方式错误");
        }
        if (userThirdPartyAccounts.size() <= 0 ){
            throw new IllegalArgumentException("请先绑定收款方式");
        }
        UserThirdPartyAccount userThirdPartyAccount = userThirdPartyAccounts.get(0);
        //判断当日提现次数是否上限
        Integer isCashNum = getInteger(transferConfig, userThirdPartyAccount);
        TransferOrder transferOrder = null ;
        if (userThirdPartyAccount.getAccountType() == 1){
            //判断是否微信授权
//            userWxOpenService.isOauthThrow(userId);

            transferOrder = wxTransferOrder(addTransferOrderVo , userThirdPartyAccount);
        }else{
            transferOrder =  zfbTransferOrder(addTransferOrderVo , userThirdPartyAccount);
        }
        if (transferOrder == null){
            throw new IllegalArgumentException("系统繁忙，请稍后在试");
        }
        if (transferOrder.getRefundStatus() != 0){
            redisUtil.setForObjectTimeCustom(RedisConstants.IS_CASH+userThirdPartyAccount.getAccountNum() ,
                    (isCashNum+1)+"", DateUtils.getSecondsNextEarlyMorning(), TimeUnit.SECONDS);
            redisUtil.setForObjectTimeCustom(RedisConstants.IS_CASH+userId ,
                    (isCashNum+1)+"", DateUtils.getSecondsNextEarlyMorning(), TimeUnit.SECONDS);
        }
        return transferOrder;
    }



    //判断是否可以提现
    @NotNull
    private Integer getInteger(TransferConfig transferConfig, UserThirdPartyAccount userThirdPartyAccount) {
        Integer isCashNum = 0 ;
        if (redisUtil.hasKey(RedisConstants.IS_CASH+ userThirdPartyAccount.getUserId())
                || redisUtil.hasKey(RedisConstants.IS_CASH+ userThirdPartyAccount.getUserId())){
            isCashNum = Integer.parseInt(redisUtil.get(RedisConstants.IS_CASH+ userThirdPartyAccount.getUserId()));
            if (isCashNum >= transferConfig.getCountNum()){
                throw new IllegalArgumentException("当日提现次数已上限");
            }
        }
        if (redisUtil.hasKey(RedisConstants.IS_CASH+ userThirdPartyAccount.getAccountNum())
            || redisUtil.hasKey(RedisConstants.IS_CASH+ userThirdPartyAccount.getAccountNum())){
            isCashNum = Integer.parseInt(redisUtil.get(RedisConstants.IS_CASH+ userThirdPartyAccount.getAccountNum()));
            if (isCashNum >= transferConfig.getCountNum()){
                throw new IllegalArgumentException("当日提现次数已上限");
            }
        }
        return isCashNum;
    }





    @Override
    public TransferOrder zfbTransferOrder(AddTransferOrderVo addTransferOrderVo ,UserThirdPartyAccount userThirdPartyAccount) {

        Long userId = addTransferOrderVo.getUserId();
        String refundDesc = addTransferOrderVo.getRefundDesc();
        Integer money = addTransferOrderVo.getMoney();
        TransferConfig transferConfig = addTransferOrderVo.getTransferConfig();


        String orderId = OrderNoCenter.getInstance().create();
        TransferOrder transferOrder = new TransferOrder();
        transferOrder.setTransferPosition(transferConfig.getTransferPosition());
        transferOrder.setSourceId(addTransferOrderVo.getSourceId());


        if (money >= transferConfig.getAuditThreshold()){
            transferOrder.setRefundStatus(3);
            transferOrder.setIsProcess(1);
        }else {
            //查询转账支付宝账号
            ZfbKeyVo zfbKeyVo = zfbPayKeyService.cutAppId(PayMethodEnums.TX_ZFB_USED.getMessage());
            if (zfbKeyVo == null ){
                throw new IllegalArgumentException("系统繁忙，请稍后在试");
            }
            TransferRequestDto transferRequestDto = ZfbOrderUtil.transferRequest(orderId , userThirdPartyAccount.getAccountNum() ,
                    userThirdPartyAccount.getAccountName() ,money , pagekname1+"提现", zfbKeyVo);
            if (transferRequestDto.getIstrue()){
                transferOrder.setRefundStatus(1);
            }else {
                transferOrder.setRefundStatus(0);
            }
            transferOrder.setZfbId(transferRequestDto.getZfbKeyVo().getId());
            transferOrder.setRefundBody(transferRequestDto.getMsg());
            transferOrder.setIsProcess(0);
        }


        transferOrder.setCreateTime(new Date());
        transferOrder.setOrderId(orderId);
        transferOrder.setRefundTime(new Date());
        transferOrder.setUserId(userId);
        transferOrder.setZfbName(userThirdPartyAccount.getAccountName());
        transferOrder.setZfbAccount(userThirdPartyAccount.getAccountNum());
        transferOrder.setRefundAmount(money);
        transferOrder.setRefundDesc(refundDesc);
        transferOrder.setPaymentType(0);
        save(transferOrder);


        return transferOrder;

    }
    @Autowired
    private WxPayKeyService wxPayKeyService ;
    @Override
    public TransferOrder wxTransferOrder(AddTransferOrderVo addTransferOrderVo, UserThirdPartyAccount userThirdPartyAccount) {

        Long userId = addTransferOrderVo.getUserId();
        TransferConfig transferConfig = addTransferOrderVo.getTransferConfig();
        TransferOrder transferOrder = new TransferOrder();
        transferOrder.setTransferPosition(transferConfig.getTransferPosition());
        transferOrder.setSourceId(addTransferOrderVo.getSourceId());


        String refundDesc = addTransferOrderVo.getRefundDesc();
        Integer money = addTransferOrderVo.getMoney();
        BigDecimal detailMoney = new BigDecimal(addTransferOrderVo.getMoney());
        WechatTransferBatchesParam param = new WechatTransferBatchesParam();
        String batchId = OrderNoCenter.getInstance().create();
        param.setBatchId(batchId);
        param.setTitle(refundDesc);
        param.setRemark(refundDesc);
        param.setTotalMoney(detailMoney);
        // 批量转账，可以同时转账给多人，但是不能超过3000，我这里只转账给一个人，只用来测试
        List<WechatTransferBatchesParam.transferDetail> detailList = new ArrayList<>();
        WechatTransferBatchesParam.transferDetail detail = new WechatTransferBatchesParam.transferDetail();
        detail.setBatchId(batchId);
        detail.setTotalDetailMoney(detailMoney);
        detail.setDetailRemark(refundDesc);
        detail.setOpenid(userThirdPartyAccount.getAccountNum());
        detailList.add(detail);
        param.setTransferDetailList(detailList);




        if (money >= transferConfig.getAuditThreshold()){
            transferOrder.setRefundStatus(3);
            transferOrder.setIsProcess(1);
        }else {
            //查询转账微信账号
            WxPayConfigV3 wxPayConfigV3 = wxPayKeyService.cutAppId(WxPayMethodEnums.Withdrawal_USED.getMessage());
            if (wxPayConfigV3 == null ){
                throw new IllegalArgumentException("系统繁忙，请稍后在试");
            }
            String s = WxPayTransferBatchesUtils.transferBatches(wxPayConfigV3,param,wxPayConfigV3.getWxPayClient());
//            if (StringUtils.isNotEmpty(s)){
//                transferOrder.setRefundStatus(1);
//            }else {
//                transferOrder.setRefundStatus(0);
//            }
            transferOrder.setRefundStatus(2);
            transferOrder.setWxId(wxPayConfigV3.getId().longValue());
            transferOrder.setRefundBody(s);
            transferOrder.setIsProcess(0);
        }
        transferOrder.setCreateTime(new Date());
        transferOrder.setOrderId(batchId);
        transferOrder.setRefundTime(new Date());
        transferOrder.setUserId(userId);
        transferOrder.setZfbName(userThirdPartyAccount.getAccountName());
        transferOrder.setZfbAccount(userThirdPartyAccount.getAccountNum());
        transferOrder.setRefundAmount(money);
        transferOrder.setRefundDesc(refundDesc);
        transferOrder.setPaymentType(1);
        save(transferOrder);
        return transferOrder;
    }

    @Override
    public void wxTransferOrderStatus() {
        int pageNum = 1;
        int pageSize = 10;
        boolean hasMore = true;
        while (hasMore) {
            //获取今天的日期
            // 查询第 pageNum 页数据
            Page<TransferOrder> resultPage = page(new Page<TransferOrder>(pageNum, pageSize)
                    , Wrappers.<TransferOrder>lambdaQuery()
                            .eq(TransferOrder::getPaymentType  , 1)
                            .eq(TransferOrder::getRefundStatus , 2));
            List<TransferOrder> dataList = resultPage.getRecords();

            if(dataList.size() <= 0)break;
            // 判断是否还有数据
            if (dataList.size() >= pageSize) {
                pageNum++;
            } else {
                hasMore = false;
            }
            log.info("dataList:"+dataList.size());
            // 处理数据
            List<TransferOrder> updateDataList = new ArrayList<>();
            for (int i = 0; i <dataList.size() ; i++) {

                TransferOrder transferOrder = dataList.get(i);
                log.info("transferOrder:"+i+"  transferOrder:"+transferOrder);
                WxPayConfigV3 wxPayConfigV3 = wxPayKeyService.getWxPayConfigV3(transferOrder.getWxId(), null);
                TransferBatch transferBatch =  WxPaySearchTransfreUtil.searchByOrderId(wxPayConfigV3 , transferOrder.getOrderId() , wxPayConfigV3.getWxPayClient());
                //WAIT_PAY: 待付款确认。需要付款出资商户在商家助手小程序或服务商助手小程序进行付款确认
                //ACCEPTED:已受理。批次已受理成功，若发起批量转账的30分钟后，转账批次单仍处于该状态，可能原因是商户账户余额不足等。商户可查询账户资金流水，若该笔转账批次单的扣款已经发生，则表示批次已经进入转账中，请再次查单确认
                //PROCESSING:转账中。已开始处理批次内的转账明细单
                //FINISHED:已完成。批次内的所有转账明细单都已处理完成
                //CLOSED:已关闭。可查询具体的批次关闭原因确认
                if (transferBatch.getBatch_status().equals("FINISHED")){
                    List<TransferDetail> transferDetailList = transferBatch.getTransferDetailList();
                    if (transferDetailList.size()>0){
                        TransferDetail transferDetail = transferDetailList.get(0);
                        //NIT: 初始态。 系统转账校验中
                        //WAIT_PAY: 待确认。待商户确认, 符合免密条件时, 系统会自动扭转为转账中
                        //PROCESSING:转账中。正在处理中，转账结果尚未明确
                        //SUCCESS:转账成功
                        //FAIL:转账失败。需要确认失败原因后，再决定是否重新发起对该笔明细单的转账（并非整个转账批次单）
                        if (transferDetail.getDetail_status().equals("SUCCESS")){
                            transferOrder.setRefundStatus(1);
                            updateDataList.add(transferOrder);
                        }else if (transferDetail.getDetail_status().equals("FAIL")){
                            //转账失败
                            transferOrder.setRefundStatus(0);
                            updateDataList.add(transferOrder);
                        }
                    }
                }else if (transferBatch.getBatch_status().equals("CLOSED")){
                    //转账失败
                }
            }
            if (updateDataList.size()>0){
                updateBatchById(updateDataList);
            }
        }
    }

    public static boolean isNumber(String str) {
        Pattern pattern = Pattern.compile("^(([1-9]{1}\\d*)|([0]{1}))(\\.(\\d){0,2})?$"); // 判断小数点后2位的数字的正则表达式
        Matcher match = pattern.matcher(str);
        return match.matches();
    }






}
